<?php
/**
 * (logic) Amazon订单
 */
namespace App\Logic\Amazon;
use App\Libs\MarketplaceWebServiceOrders\OrdersMws;
use App\Libs\RequestClient;
use App\Models\Amazon\AmazonOrder;
use App\Models\Amazon\AmazonOrderAddress;
use App\Models\Amazon\AmazonOrderCondition;
use App\Models\Amazon\AmazonOrderItem;
use Illuminate\Support\Facades\DB;
class GrabOrders extends GrabCommon
{
    const GRAB_ORDERS_INTERVAL = 600;

    /**
     * 返回您在指定时间段内所创建或更新的订单。
     * API ListOrders
     * @param $account
     * @param array $con
     * @return bool
     */
    public static function listOrders($account,$con = array()){
        if(!$account)return false;
        if(!(isset($con['LastUpdatedAfter']) && $con['LastUpdatedAfter'])){
            $con['LastUpdatedAfter'] = AmazonOrderCondition::getNextStartTime($account->id);
        }
        if(!$con['LastUpdatedAfter'])return false;
        if(!(isset($con['LastUpdatedBefore']) && $con['LastUpdatedBefore'])){
            if((isset($con['Times']) && $con['Times'])){
                $con['LastUpdatedBefore'] = self::_getLastUpdatedBefore($con['LastUpdatedAfter'],$con['Times']);
            }else{
                $con['LastUpdatedBefore'] = self::_getLastUpdatedBefore($con['LastUpdatedAfter']);
            }
        }
        if(strtotime($con['LastUpdatedAfter']) >= strtotime($con['LastUpdatedBefore']))return false;
        $con['MarketplaceId'] = $account->account_country->pluck('marketplace_id')->toArray();
        $con['SellerId'] = $account->merchant;
        $con['MWSAuthToken'] = $account->mws_auth_token;
        $service = self::getRequestClient('orders',$account);
        $fm = OrdersMws::getInit();
        $param = $fm->listOrders($con);
        $data = $service->requestExe($param);
        if(!$data)return false;
        $nextToken = self::_extractListOrdersResponse($account,$service,$data);
        self::_listOrdersByNextToken($account,$service,$nextToken);
        return true;
    }

    /**
     * 使用 NextToken 参数返回下一页订单。
     * API ListOrdersByNextToken
     * @param $account
     * @param $service
     * @param $nextToken
     */
    private static function _listOrdersByNextToken($account,$service,$nextToken){
        if($nextToken){
            sleep(1);
            if(!($service instanceof RequestClient)){
                $service = self::getRequestClient('orders',$account);
            }
            $rm = OrdersMws::getInit();
            $param = $rm->listOrdersByNextToken(['SellerId'=>$account->merchant,'NextToken'=>$nextToken,'MWSAuthToken' => $account->mws_auth_token]);
            $data = $service->requestExe($param);
            $nextToken = self::_extractListOrdersResponse($account,$service,$data,true);
            self::_listOrdersByNextToken($account,$service,$nextToken);
        }
    }

    private static function _extractListOrdersResponse($account,$service,$data,$flag = false){
        $_str = $flag ? 'ListOrdersByNextTokenResult' : 'ListOrdersResult';
        $response = isset($data[$_str]['Orders']['Order']) ? $data[$_str]['Orders']['Order'] : [];
        if(isset($response['AmazonOrderId']))$response = [$response];
        $lastUpdatedBefore = isset($data['ListOrdersResult']['LastUpdatedBefore']) ? $data['ListOrdersResult']['LastUpdatedBefore'] : null;
        self::_extractAmazonOrders($account,$service,$response,$lastUpdatedBefore);
        return isset($data[$_str]['NextToken']) ? $data[$_str]['NextToken'] : null;
    }

    private static function _extractAmazonOrders($account,$service,$orders,$lastUpdatedBefore){
        try{
            DB::connection('mysql_amazon')->beginTransaction();
            foreach($orders as $order){
                if(!$order['AmazonOrderId'])continue;
                $orderItems = self::listOrderItems($account,$service,$order['AmazonOrderId']);
                if(!$orderItems)continue;
                $item = [];
                $item['amazon_order_id'] = $order['AmazonOrderId'];
                $item['purchase_date'] = gmdate('Y-m-d H:i:s',strtotime($order['PurchaseDate']));
                $item['marketplace_id'] = $order['MarketplaceId'];
                $item['sales_channel'] = $order['SalesChannel'];
                $item['order_status'] = AmazonOrder::getOrderStatusIdByStr($order['OrderStatus']);
                $orderAddress = [];
                $orderAddress['amazon_order_id'] = $order['AmazonOrderId'];
                $orderAddress['buyer_name'] = isset($order['BuyerName']) ? $order['BuyerName'] : null;
                $orderAddress['buyer_email'] = isset($order['BuyerEmail']) ? $order['BuyerEmail'] : null;
                $orderAddress['name'] = isset($order['ShippingAddress']['Name']) ? $order['ShippingAddress']['Name'] : null;
                $orderAddress['city'] = isset($order['ShippingAddress']['City']) ? $order['ShippingAddress']['City'] : null;
                $orderAddress['state'] = isset($order['ShippingAddress']['StateOrRegion']) ? $order['ShippingAddress']['StateOrRegion'] : null;
                $orderAddress['postal_code'] = isset($order['ShippingAddress']['PostalCode']) ? $order['ShippingAddress']['PostalCode'] : null;
                $orderAddress['country'] = isset($order['ShippingAddress']['CountryCode']) ? $order['ShippingAddress']['CountryCode'] : null;
                $orderAddress['phone'] = isset($order['ShippingAddress']['Phone']) ? $order['ShippingAddress']['Phone'] : null;
                $orderItem = [];
                foreach($orderItems as $_k => $items){
                    $orderItem[$_k]['amazon_order_id'] = $order['AmazonOrderId'];
                    $orderItem[$_k]['order_item_id'] = $items['OrderItemId'];
                    $orderItem[$_k]['account_id'] = $account->id;
                    $orderItem[$_k]['sku'] = $items['SellerSKU'];
                    $orderItem[$_k]['asin'] = $items['ASIN'];
                    $orderItem[$_k]['quantity'] = $items['QuantityOrdered'] ?? 0;
                    $orderItem[$_k]['quantity_shipped'] = $items['QuantityShipped'] ?? 0;
                    $orderItem[$_k]['currency'] = isset($items['ItemPrice']['CurrencyCode']) ? $items['ItemPrice']['CurrencyCode'] : null;
                    $orderItem[$_k]['price'] =  isset($items['ItemPrice']['Amount']) ? $items['ItemPrice']['Amount'] : 0;
                    $orderItem[$_k]['shipping_price'] =  isset($items['ShippingPrice']['Amount']) ? $items['ShippingPrice']['Amount'] : 0;
                    $orderItem[$_k]['gift_wrap_price'] =  isset($items['GiftWrapPrice']['Amount']) ? $items['GiftWrapPrice']['Amount'] : 0;
                    $orderItem[$_k]['shipping_discount'] =  isset($items['ShippingDiscount']['Amount']) ? $items['ShippingDiscount']['Amount'] : 0;
                    $orderItem[$_k]['promotion_discount'] =  isset($items['PromotionDiscount']['Amount']) ? $items['PromotionDiscount']['Amount'] : 0;
                }
                self::_store($item,$orderAddress,$orderItem);
                sleep(1);
            }
            $lastUpdatedBefore && AmazonOrderCondition::upNextStartTime($account->id,$lastUpdatedBefore);
            DB::connection('mysql_amazon')->commit();
        }catch (\Exception $e){
            DB::connection('mysql_amazon')->rollBack();
            report($e);
        }
    }

    private static function _store($item,$orderAddress,$orderItem){
        $amazonOrder = AmazonOrder::query()->firstOrNew(['amazon_order_id' => $item['amazon_order_id']],['marketplace_id' => $item['marketplace_id']]);
        foreach ($item as $k => $value ){
            if($k == 'amazon_order_id')continue;
            $amazonOrder->{$k} = $value;
        }
        $amazonOrder->save();
        $amazonOrderAddress = AmazonOrderAddress::query()->firstOrNew(['amazon_order_id' => $item['amazon_order_id']]);
        foreach ($orderAddress as $k => $value ){
            if($k == 'amazon_order_id')continue;
            $amazonOrderAddress->{$k} = $value;
        }
        $amazonOrderAddress->save();
        foreach ($orderItem as $_orderItem ){
            $_orderItemTemp = [];
            foreach ($_orderItem as $k => $value){
                if($k == 'order_item_id')continue;
                $_orderItemTemp[$k] = $value;
            }
            AmazonOrderItem::query()->updateOrCreate(['order_item_id' => $_orderItem['order_item_id']],$_orderItemTemp);
        }
    }

    /**
     * 弃用
     * @param $item
     * @param $orderAddress
     * @param $orderItem
     */
    private static function _store2($item,$orderAddress,$orderItem){
        $amazonOrder = self::_getAmazonOrder($item['amazon_order_id']);
        if($amazonOrder){
            foreach ($item as $k => $value ){
                $amazonOrder->{$k} = $value;
            }
            $amazonOrder->save();
            $amazonOrderAddress = AmazonOrderAddress::where('amazon_order_id',$item['amazon_order_id'])->first();
            if(!$amazonOrderAddress){
                AmazonOrderAddress::create($orderAddress);
            }else{
                foreach ($orderAddress as $k => $value ){
                    $amazonOrderAddress->{$k} = $value;
                }
                $amazonOrderAddress->save();
            }
            foreach ($orderItem as $_orderItem ){
                $amazonOrderItem = AmazonOrderItem::where('order_item_id',$_orderItem['order_item_id'])->first();
                if(!$amazonOrderItem){
                    AmazonOrderItem::create($_orderItem);
                }else{
                    foreach ($_orderItem as $k => $value){
                        $amazonOrderItem->{$k} = $value;
                    }
                    $amazonOrderItem->save();
                }
            }
        }else{
            $amazonOrder = AmazonOrder::create($item);
            $amazonOrder->address()->create($orderAddress);
            $amazonOrder->items()->createMany($orderItem);
        }
    }

    private static function _getAmazonOrder($amazonOrderId){
        return AmazonOrder::where('amazon_order_id',$amazonOrderId)->first();
    }

    //-------------------------------------OrderItems------------------------------------------------------------
    /**
     * 根据指定的 AmazonOrderId 返回订单商品。
     * @param $service
     * @param $account
     * @param $amazonOrderId
     * @return array|null
     */
    public static function listOrderItems($account,$service,$amazonOrderId){
        if(!($service instanceof RequestClient)){
            $service = self::getRequestClient('orders',$account);
        }
        $fm = OrdersMws::getInit();
        $param = $fm->listOrderItems(['SellerId'=>$account->merchant,'AmazonOrderId'=>$amazonOrderId,'MWSAuthToken' => $account->mws_auth_token]);
        $data = $service->requestExe($param);
        return self::_extractListOrderItemsResponse($data);
    }

    /**
     * 使用 NextToken 参数返回下一页订单商品。
     * API ListOrderItemsByNextToken
     * @param $account
     * @param $service
     * @param $nextToken
     */
    private static function _listOrderItemsByNextToken($account,$service,$nextToken){
        if($nextToken){
            sleep(2);
            if(!($service instanceof RequestClient)){
                $service = self::getRequestClient('orders',$account);
            }
            $rm = OrdersMws::getInit();
            $param = $rm->listOrderItemsByNextToken(['SellerId'=>$account->merchant,'NextToken'=>$nextToken,'MWSAuthToken' => $account->mws_auth_token]);
            $data = $service->requestExe($param);
            $nextToken = self::_extractListOrderItemsResponse($data,true);
            self::_listOrderItemsByNextToken($account,$service,$nextToken);
        };
    }

    private static function _extractListOrderItemsResponse($data,$flag = false){
        $_str = $flag ? 'ListOrderItemsByNextTokenResult' : 'ListOrderItemsResult';
        $amazonOrderId = isset($data[$_str]['AmazonOrderId']) ? $data[$_str]['AmazonOrderId'] : null;
        if(!$amazonOrderId)return null;
        $response = isset($data[$_str]['OrderItems']['OrderItem']) ? $data[$_str]['OrderItems']['OrderItem'] : null;
        if(!$response)return null;
        if(isset($response['OrderItemId']))$response = [$response];
        return $response;
    }

    private static function _getLastUpdatedBefore($lastUpdatedAfter,$times = 1){
        $lastUpdatedBefore = strtotime($lastUpdatedAfter) + self::GRAB_ORDERS_INTERVAL * $times;
        $lastUpdatedBeforeMax = time() - 120;
        $time = min($lastUpdatedBefore,$lastUpdatedBeforeMax);
        return getDateFormat(date('Y-m-d H:i:s',$time - self::GRAB_ZONE_INTERVAL));
    }

    //-------------------------------------GetOrder------------------------------------------------------------

    /**
     * 根据您指定的 AmazonOrderId 值返回订单。
     * API GetOrder
     * @param $account
     * @param array $con
     * @return bool
     */
    public static function getOrder($account,$con = array()){
        if(!$account)return false;
        if(!isset($con['AmazonOrderId'])||!$con['AmazonOrderId'])return false;
        $con['SellerId'] = $account->merchant;
        $con['MWSAuthToken'] = $account->mws_auth_token;
        $service = self::getRequestClient('orders',$account);
        $fm = OrdersMws::getInit();
        $param = $fm->getOrder($con);
        $data = $service->requestExe($param);
        if(!$data)return false;
        return self::_extractGetOrderResponse($account,$service,$data);
    }

    private static function _extractGetOrderResponse($account,$service,$data){
        $response = isset($data['GetOrderResult']['Orders']['Order']) ? $data['GetOrderResult']['Orders']['Order'] : [];
        if(!$response)return false;
        if(isset($response['AmazonOrderId']))$response = [$response];
        try{
            self::_extractAmazonOrders($account,$service,$response,null);
            return true;
        }catch (\Exception $e){
            return false;
        }
    }
}
